/**
 * 同义词接口
 */
import { directus, getItems, getItemById, createItem, updateItem, deleteItem } from '../directus'

/** 集合名*/
export const COLLECTION_SYNONYM = 'synonym' as const

/** 导入接口 */
export const IMPORT_SYNONYM_ENDPOINT = '/utils/import/synonym' as const

/** 状态 */
export type SynonymStatus = 'published' | 'draft' | 'archived'

/** 同义词实体 */
export interface SynonymItem {
    id: number | string
    querys?: string
    status?: SynonymStatus
    date_created?: string
    date_updated?: string
    user_created?: any
    user_updated?: any
}

/** 列表查询参数 */
export interface SynonymListParams {
    page?: number
    pageSize?: number
    keyword?: string
    sort?: string | string[]
    excludeStatus?: SynonymStatus
    signal?: AbortSignal
}

/** 列表返回结果 */
export interface SynonymListResult {
    list: SynonymItem[]
    total: number
}

/** 导出参数 */
export interface SynonymExportParams {
    ids?: Array<number | string>
    keyword?: string
    excludeStatus?: SynonymStatus
    sort?: string | string[]
    format?: 'csv' | 'json'
    signal?: AbortSignal
}

/* ------------------------- 公共常量/工具函数 ------------------------- */

const FIELDS_BASE = ['id', 'querys', 'status', 'date_created'] as const
type FieldKey = (typeof FIELDS_BASE)[number]

const normalizeSort = (sort?: string | string[]) =>
    Array.isArray(sort) ? sort.filter(Boolean) : sort ? [sort] : []

const safeTrim = (s?: string) => (typeof s === 'string' ? s.trim() : '')

const buildFilter = ({
    excludeStatus,
    keyword,
    ids,
}: {
    excludeStatus?: SynonymStatus
    keyword?: string
    ids?: Array<number | string>
}) => {
    const filter: Record<string, any> = {}
    if (excludeStatus) filter.status = { _neq: excludeStatus }
    const kw = safeTrim(keyword)
    if (kw) filter._or = [{ querys: { _icontains: kw } }]
    if (ids && ids.length) filter.id = { _in: ids }
    return filter
}

const dateStamp = () => {
    const d = new Date()
    const p = (n: number) => String(n).padStart(2, '0')
    return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}_${p(d.getHours())}${p(
        d.getMinutes()
    )}${p(d.getSeconds())}`
}

const toCsv = (rows: Array<Record<string, any>>, header: string[]) => {
    const esc = (v: any) => {
        const s = String(v ?? '')
        return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s
    }
    const lines = [header, ...rows.map((r) => header.map((h) => r[h]))]
        .map((arr) => arr.map(esc).join(','))
        .join('\n')
    return '\uFEFF' + lines
}

/* ------------------------------ 列表 ------------------------------ */

/**
 * 获取同义词分页列表
 */
export async function getSynonymList(params: SynonymListParams = {}): Promise<SynonymListResult> {
    const {
        page = 1,
        pageSize = 25,
        keyword = '',
        sort = ['-id'],
        excludeStatus = 'archived',
        signal,
    } = params

    const filter = buildFilter({ excludeStatus, keyword })

    const res: any = await getItems<SynonymItem>(COLLECTION_SYNONYM, {
        page,
        limit: pageSize,
        fields: FIELDS_BASE as unknown as FieldKey[],
        sort: normalizeSort(sort),
        filter,
        meta: 'filter_count',
        signal,
    })

    const list: SynonymItem[] = res?.data ?? res ?? []
    const total: number = res?.meta?.filter_count ?? res?.meta?.total_count ?? list.length
    return { list, total }
}

/* ------------------------------ 详情 ------------------------------ */

/** 详情 */
export function getSynonymById(id: number | string) {
    return getItemById<SynonymItem>(COLLECTION_SYNONYM, id, {
        fields: [
            'id',
            'querys',
            'status',
            'date_created',
            'date_updated',
            'user_created',
            'user_updated',
        ],
    })
}

/**
 * 详情
 */
export async function getSynonymDetail(
    id: number | string
): Promise<{ id: number | string; words: string; enabled: boolean; raw: SynonymItem }> {
    const res: any = await getSynonymById(id)
    const raw: SynonymItem = res?.data ?? res ?? ({} as any)

    const words = String(raw?.querys ?? '')
        .replace(/｜/g, '|')
        .split('|')
        .map((s) => s.trim())
        .filter(Boolean)
        .filter((v, i, a) => a.indexOf(v) === i)
        .join('|')

    const enabled = (raw?.status ?? 'draft') === 'published'
    return { id: raw?.id!, words, enabled, raw }
}

/* ------------------------------ 新增/编辑/删除 ------------------------------ */

/** 新增 */
export function createSynonym(payload: Partial<SynonymItem> | string, status: SynonymStatus = 'draft') {
    const body: Partial<SynonymItem> =
        typeof payload === 'string' ? { querys: payload, status } : { status: payload.status ?? status, ...payload }
    return createItem<SynonymItem>(COLLECTION_SYNONYM, body)
}

/** 更新 */
export function updateSynonym(id: number | string, payload: Partial<SynonymItem>) {
    return updateItem<SynonymItem>(COLLECTION_SYNONYM, id, payload)
}

/** 删除（单个） */
export function deleteSynonym(id: number | string) {
    return deleteItem(COLLECTION_SYNONYM, id)
}

/** 批量删除 */
export async function deleteSynonyms(ids: Array<number | string>) {
    if (!ids?.length) return
    await Promise.all(ids.map((id) => deleteSynonym(id)))
}

/** 设置状态 */
export function setSynonymStatus(id: number | string, status: SynonymStatus) {
    return updateSynonym(id, { status })
}

/** 启用 => published */
export function enableSynonym(id: number | string) {
    return setSynonymStatus(id, 'published')
}

/** 停用 => draft */
export function disableSynonym(id: number | string) {
    return setSynonymStatus(id, 'draft')
}

/* ------------------------------ 导入 ------------------------------ */

/**
 * 导入文件
 */
export async function importSynonymsFile(
    file: File | Blob,
    filename?: string,
    opts?: { signal?: AbortSignal; extra?: Record<string, string | number | boolean> }
): Promise<any> {
    const fd = new FormData()
    if (file instanceof File) {
        fd.append('file', file, file.name)
    } else {
        fd.append('file', file, filename || 'synonyms.csv')
    }
    if (opts?.extra) {
        Object.entries(opts.extra).forEach(([k, v]) => fd.append(k, String(v)))
    }

    const res = await directus.post(IMPORT_SYNONYM_ENDPOINT, fd, {
        withCredentials: true,
        signal: opts?.signal as any,
    })
    return res?.data ?? {}
}

/* ------------------------------ 导出 ------------------------------ */

/** 导出 */
export async function exportSynonyms(params: SynonymExportParams = {}) {
    const {
        ids,
        keyword = '',
        excludeStatus = 'archived',
        sort = ['-id'],
        format = 'csv',
        signal,
    } = params

    const filter = buildFilter({ excludeStatus, keyword, ids })
    const limit = 500
    let page = 1
    const all: SynonymItem[] = []
    while (true) {
        const res: any = await getItems<SynonymItem>(COLLECTION_SYNONYM, {
            page,
            limit,
            fields: FIELDS_BASE as unknown as FieldKey[],
            sort: normalizeSort(sort),
            filter,
            signal,
        })
        const chunk: SynonymItem[] = res?.data ?? res ?? []
        all.push(...chunk)
        if (!chunk.length || chunk.length < limit) break
        page += 1
    }

    const rows = all.map((x) => ({
        querys: x.querys || '',
        status: x.status || 'draft',
        date_created: x.date_created || '',
    }))

    const stamp = dateStamp()

    if (format === 'json') {
        const blob = new Blob([JSON.stringify(rows, null, 2)], {
            type: 'application/json;charset=utf-8',
        })
        return { blob, filename: `synonym_${stamp}_${rows.length}.json`, count: rows.length }
    }

    const header = ['querys', 'status', 'date_created']
    const csv = toCsv(rows, header)

    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })
    return { blob, filename: `synonym_${stamp}_${rows.length}.csv`, count: rows.length }
}
